# _*_ coding utf-8 _*_
# FILENAME：.py
# DESCRIPTION: 资源文件工具类
# AUTH: ZB
# DATE: 2022/6/2 10:00 下午

# 导入模块
import os
import threading
import time

import pandas as pd

# 获取ICO
from constant import CacheType, DB_CON_URI, UploadType, CalculateType, Scene

# 获取缓存路径
from models.baseModel import get_session
from models.bomModel import BomDetailsModel
from models.factoryModel import FactoryModel
from models.factoryTransportTimeModel import FactoryTransportTimeDetailsModel
from models.inventoryModel import InventoryDetailsModel
from models.operationTimeModel import OperationTimeDetailsModel
from models.orderPlanModel import OrderPlanDetailsModel
from models.partsLoadDelayTimeModel import PartsLoadDelayTimeDetailsModel
from models.partsModel import PartsDetailsModel
from models.produceQueueModel import ProduceQueueDetailsModel
from models.produceSpeedModel import ProduceSpeedDetailsModel
from models.requireModel import RequireDetailsModel, RequireModel
from models.requireSummaryModel import RequireSummaryModel
from models.shipperModel import ShipperDetailsModel
from models.suppllierAddressModel import SupplierAddressDetailsModel
from models.suppllierDistanceModel import SupplierDistanceDetailsModel
from models.suppllierDurationModel import SupplierDurationDetailsModel


"""
缓存锁
"""
class Lock:
    lock = {}

    """
    获取锁key
    """
    @staticmethod
    def get_lock_key(type, version_id):
        return str(type) + "_" + str(version_id)

    """
    设置锁
    """
    @staticmethod
    def set_lock(type, version_id):
        lock_key = Lock.get_lock_key(type, version_id)
        if lock_key in Lock.lock:
            return False
        else:
            Lock.lock[lock_key] = 1
            return True

    """
    删除锁
    """
    @staticmethod
    def del_lock(type, version_id):
        lock_key = Lock.get_lock_key(type, version_id)
        del Lock.lock[lock_key]

    """
    获取锁key
    """
    @staticmethod
    def is_locked(type, version_id):
        lock_key = Lock.get_lock_key(type, version_id)
        if lock_key in Lock.lock:
            return True
        else:
            return False


"""
缓存
"""
class Cache:
    base_path = os.getcwd() + "/data/"

    def __init__(self, type, version_id):
        super(Cache, self).__init__()
        self.__type = type
        self.__version_id = version_id

    """
    缓存
    """
    def cache(self, is_force=False):
        type = self.__type
        version_id = self.__version_id

        # 设置缓存锁
        if not is_force:
            if not Lock.set_lock(type, version_id):
                return False
        else:
            while not Lock.set_lock(type, version_id):
                time.sleep(1)

        # 创建根路径
        os.makedirs(self.base_path, exist_ok=True)

        path = self._get_cache_path()
        sql = None
        files = []
        if type == CacheType.BOM.value:
            sql = "select * from " + BomDetailsModel.__tablename__ + " where " + BomDetailsModel.bom_id.key + " = " + str(version_id) + " and is_del = 0;"
        elif type == CacheType.PRODUCE_SPEED.value:
            sql = "select * from " + ProduceSpeedDetailsModel.__tablename__ + " where " + ProduceSpeedDetailsModel.produce_speed_id.key + " = " + str(version_id) + " and is_del = 0;"
        elif type == CacheType.PRODUCE_QUEUE.value:
            sql = "select * from " + ProduceQueueDetailsModel.__tablename__ + " where " + ProduceQueueDetailsModel.produce_queue_id.key + " = " + str(version_id) + " and is_del = 0;"
        elif type == CacheType.PARTS.value:
            sql = "select * from " + PartsDetailsModel.__tablename__ + " where " + PartsDetailsModel.parts_id.key + " = " + str(version_id) + " and is_del = 0;"
        elif type == CacheType.PARTS_LOAD_DELAY_TIME.value:
            sql = "select * from " + PartsLoadDelayTimeDetailsModel.__tablename__ + " where " + PartsLoadDelayTimeDetailsModel.parts_load_delay_time_id.key + " = " + str(version_id) + " and is_del = 0;"
        elif type == CacheType.INVENTORY.value:
            sql = "select * from " + InventoryDetailsModel.__tablename__ + " where " + InventoryDetailsModel.inventory_id.key + " = " + str(version_id) + " and is_del = 0;"
        elif type == CacheType.SHIPPER.value:
            sql = "select * from " + ShipperDetailsModel.__tablename__ + " where " + ShipperDetailsModel.shipper_id.key + " = " + str(version_id) + " and is_del = 0;"
        elif type == CacheType.OPERATION_TIME.value:
            sql = "select * from " + OperationTimeDetailsModel.__tablename__ + " where " + OperationTimeDetailsModel.operation_time_id.key + " = " + str(version_id) + " and is_del = 0;"
        elif type == CacheType.FACTORY_TRANSPORT_TIME.value:
            sql = "select * from " + FactoryTransportTimeDetailsModel.__tablename__ + " where " + FactoryTransportTimeDetailsModel.factory_transport_time_id.key + " = " + str(version_id) + " and is_del = 0;"
        elif type == CacheType.SUPPLIER_DISTANCE.value:
            sql = "select * from " + SupplierDistanceDetailsModel.__tablename__ + " where " + SupplierDistanceDetailsModel.supplier_distance_id.key + " = " + str(version_id) + " and is_del = 0;"
        elif type == CacheType.SUPPLIER_DURATION.value:
            sql = "select * from " + SupplierDurationDetailsModel.__tablename__ + " where " + SupplierDurationDetailsModel.supplier_duration_id.key + " = " + str(version_id) + " and is_del = 0;"
        elif type == CacheType.SUPPLIER.value:
            sql = "select * from " + SupplierAddressDetailsModel.__tablename__ + " where " + SupplierAddressDetailsModel.supplier_id.key + " = " + str(version_id) + " and is_del = 0;"
        elif type == CacheType.REQUIRE.value:
            sql = "select f.name as factory_name, rd.* from " + RequireDetailsModel.__tablename__ + " as rd " + \
                  " left join `" + RequireModel.__tablename__ + "` as r on r." + RequireModel.id.key + " = rd." + RequireDetailsModel.require_id.key + \
                  " left join " + FactoryModel.__tablename__ + " as f on f." + FactoryModel.id.key + " = r." + RequireModel.factory_id.key + \
                  " where rd." + RequireDetailsModel.require_id.key + " = " + str(version_id) + " and rd.is_del = 0;"
        elif type == CacheType.REQUIRE_SUMMARY.value:
            session = get_session()
            require_summary = session.query(RequireSummaryModel).filter(RequireSummaryModel.id == self.__version_id).first()
            session.close()
            # 焊装
            if require_summary.weld_version_id and require_summary.weld_version_id > 0:
                cache = Cache(CacheType.REQUIRE.value, require_summary.weld_version_id)
                files.append(cache.get_cache())
            # 涂装
            if require_summary.paint_version_id and require_summary.paint_version_id > 0:
                cache = Cache(CacheType.REQUIRE.value, require_summary.paint_version_id)
                files.append(cache.get_cache())
            # 总装
            if require_summary.summary_version_id and require_summary.summary_version_id > 0:
                cache = Cache(CacheType.REQUIRE.value, require_summary.summary_version_id)
                files.append(cache.get_cache())
        elif type == CacheType.ORDER_PLAN.value:
            sql = "select * from " + OrderPlanDetailsModel.__tablename__ + " where " + OrderPlanDetailsModel.order_plan_id.key + " = " + str(version_id) + " and is_del = 0;"
        else:
            return False

        result = False
        try:
            # 判断缓存文件是否存在
            is_cached = os.path.isfile(path)
            if is_cached:
                # 删除文件
                os.remove(path)
            # 写入缓存
            if sql:
                pd.read_sql(sql, DB_CON_URI).to_csv(path, index=False)
            elif files:
                all_df = []
                for file in files:
                    all_df.append(pd.read_csv(file))
                pd.concat(all_df, axis=0, ignore_index=True).to_csv(path, index=False)
            result = True
        finally:
            # 删除缓存锁
            Lock.del_lock(type, version_id)
            return result


    """
    获取缓存文件
    """
    def get_cache(self):
        type = self.__type
        version_id = self.__version_id

        # 获取缓存路径
        path = self._get_cache_path()

        # 判断文件是否存在
        is_cached = os.path.isfile(path)
        if is_cached:
            # 判断是否在缓存中, 若正在缓存中则一直等待到缓存完成
            while Lock.is_locked(type, version_id):
                time.sleep(1)
            return path
        else:
            self.cache()
            return path


    """
    获取缓存文件路径
    """
    def _get_cache_path(self):
        type = self.__type
        version_id = self.__version_id

        if type == CacheType.BOM.value:
            path = self.base_path + "BOM_" + str(version_id) + ".csv"
        elif type == CacheType.PRODUCE_SPEED.value:
            path = self.base_path + "生产速度_" + str(version_id) + ".csv"
        elif type == CacheType.PRODUCE_QUEUE.value:
            path = self.base_path + "生产队列_" + str(version_id) + ".csv"
        elif type == CacheType.PARTS.value:
            path = self.base_path + "零件基础信息_" + str(version_id) + ".csv"
        elif type == CacheType.PARTS_LOAD_DELAY_TIME.value:
            path = self.base_path + "零件装配延误时间_" + str(version_id) + ".csv"
        elif type == CacheType.INVENTORY.value:
            path = self.base_path + "现有库存_" + str(version_id) + ".csv"
        elif type == CacheType.SHIPPER.value:
            path = self.base_path + "承运商信息_" + str(version_id) + ".csv"
        elif type == CacheType.OPERATION_TIME.value:
            path = self.base_path + "作业时间_" + str(version_id) + ".csv"
        elif type == CacheType.FACTORY_TRANSPORT_TIME.value:
            path = self.base_path + "厂内运行时间_" + str(version_id) + ".csv"
        elif type == CacheType.SUPPLIER_DISTANCE.value:
            path = self.base_path + "供应商距离_" + str(version_id) + ".csv"
        elif type == CacheType.SUPPLIER_DURATION.value:
            path = self.base_path + "供应商路程时间_" + str(version_id) + ".csv"
        elif type == CacheType.SUPPLIER.value:
            path = self.base_path + "供应商地址_" + str(version_id) + ".csv"
        elif type == CacheType.REQUIRE.value:
            path = self.base_path + "零件需求_" + str(version_id) + ".csv"
        elif type == CacheType.REQUIRE_SUMMARY.value:
            path = self.base_path + "零件需求汇总_" + str(version_id) + ".csv"
        elif type == CacheType.ORDER_PLAN.value:
            path = self.base_path + "排单计划_" + str(version_id) + ".csv"
        else:
            return

        return path

    """
    获取缓存类型
    scene: 场景值 1、上传  3、运算
    stype: 场景中对应的类型
    """

    @staticmethod
    def get_cache_type(scene, stype):
        if scene == Scene.UPLOAD.value:
            if stype == UploadType.BOM.value:
                type = CacheType.BOM.value
            elif stype == UploadType.PRODUCE_SPEED.value:
                type = CacheType.PRODUCE_SPEED.value
            elif stype == UploadType.PRODUCE_QUEUE.value:
                type = CacheType.PRODUCE_QUEUE.value
            elif stype == UploadType.PARTS.value:
                type = CacheType.PARTS.value
            elif stype == UploadType.PARTS_LOAD_DELAY_TIME.value:
                type = CacheType.PARTS_LOAD_DELAY_TIME.value
            elif stype == UploadType.INVENTORY.value:
                type = CacheType.INVENTORY.value
            elif stype == UploadType.SHIPPER.value:
                type = CacheType.SHIPPER.value
            elif stype == UploadType.OPERATION_TIME.value:
                type = CacheType.OPERATION_TIME.value
            elif stype == UploadType.FACTORY_TRANSPORT_TIME.value:
                type = CacheType.FACTORY_TRANSPORT_TIME.value
            elif stype == UploadType.SUPPLIER_DISTANCE.value:
                type = CacheType.SUPPLIER_DISTANCE.value
            elif stype == UploadType.SUPPLIER_DURATION.value:
                type = CacheType.SUPPLIER_DURATION.value
            elif stype == UploadType.SUPPLIER.value:
                type = CacheType.SUPPLIER.value
            elif stype == UploadType.REQUIRE.value:
                type = CacheType.REQUIRE.value
            else:
                return
        elif scene == Scene.CALCULATE.value:
            if stype == CalculateType.REQUIRE.value:
                type = CacheType.REQUIRE.value
            elif stype == CalculateType.REQUIRE_SUMMARY.value:
                type = CacheType.REQUIRE_SUMMARY.value
            elif stype == CalculateType.ORDER_PLAN.value:
                type = CacheType.ORDER_PLAN.value
            else:
                return
        else:
            return

        return type


"""
异步缓存
"""
class CacheThread(threading.Thread):
    def __init__(self, type, version_id):
        super(CacheThread, self).__init__()  # 重构run函数必须写
        self.__type = type
        self.__version_id = version_id

    def run(self):
        cache = Cache(self.__type, self.__version_id)
        cache.cache(True)